#ifndef FTP_DEF
#define FTP_DEF 
#include<string.h>
#include <stdio.h>
#define PORT_CONTROL_MESSAGE 12139
#define PORT_DATA 12138
#define BYTE_LENGTH 1024
#define N 50
const char* READ_BINARY = "rb";
const char* WRITE_BINARY = "wb";
const char* READ_ASCII = "r";
const char* WRITE_ASCII = "w";
const char* HELP = "help";
const char* GET = "get";
const char* PUT = "put";
const char* DELETE = "delete";
const char* LS = "ls";
const char* CD = "cd";
const char* MKDIR = "mkdir";
const char* PWD = "pwd";
const char* QUIT = "quit";
const char* FAILED="failed";
char* STATUS_MSG="200 Command okay";
const char* SET = "set";
const char* TRANS_BINARY = "binary";
const char* TRANS_ASCII = "ascii";

enum COMMAND_TYPE {C_HELP, C_QUIT, C_LS, C_GET, C_PUT, C_DELETE, C_CD, C_MKDIR, C_PWD, C_UNKOWN, C_SET };

// function declaration
void remove_space_both_ends(char s[]);
void get_aliant_filename(char filename[]);
void parse_filename_from_path(const char path[], char filename[]);
int transfer_mode_to_int(char* mode); 
int set_transfer_mode(int* present_mode, char* user_command);
const char* get_read_mode(const int present_mode);
const char* get_write_mode(const int present_mode);
const char* get_transfer_mode(const int present_mode);

enum COMMAND_TYPE check_command(char* user_command){
        remove_space_both_ends(user_command);
        if (strcmp(user_command,HELP) == 0){
            return C_HELP;
        } else if (strcmp(user_command,QUIT) == 0){
            return C_QUIT;
        } else if (strcmp(user_command,LS) == 0){                     
            return C_LS;
        } else if (strncmp(user_command, GET, 3) == 0 
                    && strlen(user_command) > 3 
                    && (user_command[3] == ' ' ||user_command[3] == '\t')){
            return C_GET;
        } else if (strncmp(user_command,PUT, 3) == 0
                    && strlen(user_command) > 3 
                    && (user_command[3] == ' ' ||user_command[3] == '\t')){
            return C_PUT;
        } else if (strncmp(user_command,DELETE, 6) == 0
                    && strlen(user_command) > 6
                    && (user_command[6] == ' ' ||user_command[6] == '\t')){
            return C_DELETE;
        } else if (strncmp(user_command,CD, 2) == 0
                    && strlen(user_command) > 2 
                    && (user_command[2] == ' ' ||user_command[2] == '\t')){
            return C_CD;
        }else if (strncmp(user_command,MKDIR, 5) == 0
                    && strlen(user_command) > 5
                    && (user_command[5] == ' ' ||user_command[5] == '\t')){
            return C_MKDIR;
        }else if (strcmp(user_command,PWD) == 0){
            return C_PWD;
        }else if (strncmp(user_command,SET, 3) == 0
                    && strlen(user_command) > 3
                    && (user_command[3] == ' ' ||user_command[3] == '\t')){
            return C_SET;         
                    }
        return C_UNKOWN;
}

// get a array of char and remove its spaces and tabs in head and tail
void remove_space_both_ends(char s[]){
    int h = 0,t = 0, len = 0;
    len = strlen(s);
    while((h<len)&&(s[h] == ' ' || s[h] == '\t')){
        h++;
    }
    t = len -1;
    while((t>h)&&(s[t] == ' ' || s[t] == '\t')){
        t--;
    }
    for(int i = h; i <= t; ++i){
        s[i - h] =  s[i];
    }
    s[t-h+1] = '\0';
    return;
}

//Get aliant filename, if already exist, add numberic suffix
void get_aliant_filename(char filename[]){
    
    FILE* this_file = NULL;

    if ( (this_file = fopen(filename, "rb")) != NULL){
        fclose(this_file);
        //printf("File <%s> already exists.\n", filename); 
        char name[N] = {0};
        char ver_num[N] = {0};
        char suffix[N] = {0};
        char new_filename[BYTE_LENGTH] = {0};
        int len = strlen(filename);
        int p = len;
        for(int i = 0; i < len;++i)
        if(filename[i] == '.'){
            p = i;
            name[i] = '_';
            name[i+1] = '\0';
            break;
        }else{
            name[i] = filename[i];
        }
        if( p == len ){
            name[p] = '_';
            name[p+1] = '\0';
        }
        for(int i = p; i < len;++i){
            suffix[i-p] = filename[i];
        }
        suffix[len-p] = '\0';

        int version_num = 0;
        while(++ version_num){
            sprintf(ver_num, "%d", version_num);
            memset(new_filename, 0, sizeof(new_filename));
            strcat(new_filename, name);
            strcat(new_filename, ver_num);
            strcat(new_filename, suffix);
            if((this_file = fopen(new_filename, "rb")) == NULL){
                strcpy(filename, new_filename);
                break;
            } else{
                fclose(this_file);
            }
        }
    }
}

void parse_filename_from_path(const char path[], char filename[]){
    const char* p = path;
    const char* after_last_slash = NULL;
    while((p = strchr(p,'/')) != NULL){
        p ++;
        after_last_slash = p;
    }
    if (after_last_slash == NULL){
        after_last_slash = path;
    }
    strcpy(filename, after_last_slash);
    return;
}

//return 0 is Ascii, 1 is Binary, -1 is illegal
int transfer_mode_to_int(char* mode){
    remove_space_both_ends(mode);
    if(strcmp(mode,TRANS_ASCII)==0){
        return 0;
    }else if (strcmp(mode,TRANS_BINARY)==0){
        return 1;
    }else{
        return -1;
    }
}

int set_transfer_mode(int* present_mode, char* user_command){
    int new_mode = 0;
    char mode[N] = {0};
    const char* mode_str = get_transfer_mode((const int)*present_mode);
    strcpy(mode, user_command + 4);
    new_mode = transfer_mode_to_int(mode);
    if(new_mode < 0){
        printf("Cannot change to this mode <%s>\n",mode);
        return -1;
    }else if (new_mode ==(*present_mode)){
        printf("Your transfer mode have been %s already.\n", mode_str);
        return 0;
    }
    (*present_mode) = new_mode;
    return 1; //modified mode
}

const char* get_read_mode(const int present_mode){
    return present_mode ? READ_BINARY:READ_ASCII;
}

const char* get_write_mode(const int present_mode){
    return present_mode ? WRITE_BINARY:WRITE_ASCII;
}

const char* get_transfer_mode(const int present_mode){
    return present_mode ? TRANS_BINARY:TRANS_ASCII;
}
#endif
